package com.lilihub.miaosha.intercepter;

import com.alibaba.fastjson.JSON;
import com.lilihub.miaosha.common.CodeMsg;
import com.lilihub.miaosha.common.Result;
import com.lilihub.miaosha.domain.MiaoshaUser;
import com.lilihub.miaosha.redis.AccessKey;
import com.lilihub.miaosha.service.MiaoshaUserService;
import com.lilihub.miaosha.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @BelongsProject: miaosha
 * @BelongsPackage: com.lilihub.miaosha.intercepter
 * @Author: LiYing
 * @CreateTime: 2021-04-30 14:41
 * @Description:
 */
@Service
public class AccessInterceptor extends HandlerInterceptorAdapter {


    @Autowired
    private MiaoshaUserService userService;

    @Autowired
    private RedisService redisService;


    /**
     * 目标方法执行前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof HandlerMethod){

            MiaoshaUser user = getMiaoshaUser(request, response);
            UserContext.setUser(user);   //将当前的线程中的对象保存起来

            HandlerMethod hm = (HandlerMethod) handler;
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);//拿到方法上的注解

            if (accessLimit == null){
                return true;
            }

            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean needLogin = accessLimit.needLogin();
            String key = request.getRequestURI();

            if (needLogin){
                if (user == null){
                    render(response,CodeMsg.SESSION_ERROR);
                    return false;
                }
                key += "_" + user.getId();
            }else{
                // do nothing
            }

            //查询访问次数----接口防刷逻辑代码
            AccessKey accessKey = AccessKey.withExpire(seconds);
            Integer count = redisService.get(accessKey, key, Integer.class);
            if (count == null){

                redisService.set(accessKey, key, 1);
            }else if (count < maxCount){

                redisService.incr(accessKey, key);
            }else{

                render(response,CodeMsg.ACCESS_LIMIT_REACHED);
                return false;
            }
        }

        return true;
    }

    private void render(HttpServletResponse response, CodeMsg cm) throws Exception {

        response.setContentType("application/json;charset=UTF-8");  //同时设置服务器和客户端都是用utf-8，解决中文乱码

        ServletOutputStream out = response.getOutputStream();

        String cmString = JSON.toJSONString(Result.error(cm));

        out.write(cmString.getBytes("UTF-8"));

        out.flush();
        out.close();

    }


    private MiaoshaUser getMiaoshaUser(HttpServletRequest request, HttpServletResponse response){

        String paramToken = request.getParameter(MiaoshaUserService.COOKI_NAME_TOKEN);
        String cookieToken = getCookieValue(request,MiaoshaUserService.COOKI_NAME_TOKEN);

        if (StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){
            return null;
        }
        String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
        MiaoshaUser user = userService.getbyToken(token,response);

        return user;

    }

    private String getCookieValue(HttpServletRequest request, String cookiNameToken) {

        Cookie[] cookies = request.getCookies();

        if (cookies == null || cookies.length <=0){
            return null;
        }

        for (Cookie c : cookies){
            if (c.getName().equals(cookiNameToken)){
                return c.getValue();
            }
        }
        return null;
    }


}
